<?php

class DBListIterator implements Iterator {
	private $index;
	private $dblist;
	public function __construct($dblist){ $this->dblist = $dblist; }
	function key() { return $this->index; }
	function current() { return $this->dblist[$this->index]; }
	function valid() { return $this->index < $this->dblist->Count();  }
	function rewind() { $this->index = -1; $this->next(); }
	function next() { $this->index++; }
}

class DBList implements IteratorAggregate,ArrayAccess,Countable {
	private $data = null;

	private $classname;
	private $sql;
	public function __construct($classname,$sql=null,$is_aggressive=false){
		$this->classname = $classname;
		$this->sql = $sql;
		$this->is_aggressive = $is_aggressive;
  }

	private $is_aggressive = true;
	public function WithIsAggressive($value){ $this->is_aggressive = $value; return $this; }

	public function count(){ $this->Initiate(); return count($this->data); }
	public function getIterator(){
		$this->Initiate();
		return new DBListIterator($this);
	}

	public function offsetExists($offset) {
		$this->Initiate();
		return isset($this->data[$offset]);
	}
	public function offsetGet($offset) {
		$this->Initiate();
		if (!isset($this->data[$offset])) throw new Exception('Offset '.$offset.' not found.');
		if ($this->data[$offset] instanceof ID) $this->data[$offset] = DBItem::RetrieveGeneric($this->classname,$this->data[$offset]);
		return $this->data[$offset];
	}
	public function offsetSet($offset, $value) {
		$this->Initiate();
		if (is_null($offset))
			$this->data[] = $value;
		else
			$this->data[$offset] = $value;
	}
	public function offsetUnset($offset) {
		$this->Initiate();
		unset($this->data[$offset]);
		$a = array();
		foreach ($this->data as $value) $a[] = $value;
		$this->data = $a;
	}
	
	public function Invalidate($new_sql) {
		$this->data = null;
		$this->sql = $new_sql;
	}
	private function Initiate() {
		if (!is_null($this->data)) return;
		$this->data = array();
		if (is_null($this->sql)) return;
		if ($this->is_aggressive) {
			$dr = Database::Execute($this->sql);
			while ($dr->Read())
				$this->data[] = DBItem::RetrieveGeneric($this->classname,$dr['id']->AsID(),$dr);
			$dr->Close();
		}
		else {
			$dr = Database::Execute($this->sql);
			while ($dr->Read())
				$this->data[] = $dr[0]->AsID();
			$dr->Close();
		}
	}

	public function LoadAll(){
		foreach ($this as $x)
			;
	}
	
	public function GetFirst(){ $this->Initiate(); return count($this)>0 ? $this[0] : null; }
	public function GetFirstOr($default){ $this->Initiate(); return count($this)>0 ? $this[0] : $default; }
	
	public function Contains($dbitem_or_id){
		$this->Initiate();
		foreach ($this->data as $xx)
			if ($xx->IsEqual($dbitem_or_id))
				return true;
		return false;
	}
	
	public function ToIDList(){
		$this->Initiate();
		$r = array();
		foreach ($this->data as $x) {
			if ($x instanceof DBItem)
				$r[] = $x->id;
			elseif ($x instanceof ID)
				$r[] = $x;
		}
		return $r;
	}
		
	public function Sort(){
		$this->LoadAll();
		usort($this->data, array($this->classname,'Compare'));
		return $this;
	}
	
	public function Merge($array){
		$this->Initiate();
		foreach ($array as $x)
			$this[] = $x;
	}

}

?>